home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / libkb100.zip / LIBKB-1.00 / SRC / _HANDLER.H next >
Text File  |  1996-07-23  |  8KB  |  280 lines

  1. /* _handler.h -- keyboard handler
  2.  * Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
  3.  * For conditions of distribution and use, see copyright notice in kb.h 
  4.  */
  5.  
  6.  
  7. /* WARNING: this file should *not* be used by applications. It is
  8.    part of the implementation of the keyboard library and is
  9.    subject to change. Applications should only use kb.h.
  10.  */
  11.  
  12.  
  13.  
  14. /***********************************************************************
  15. // int9 keyboard interrupt handler (IRQ1 keyboard data ready)
  16. //   
  17. // IMPORTANT NOTE: check your compiler flags so that no
  18. //                 stack overflow checks will be inserted here !
  19. //
  20. // Most of this code should be quite obvious.
  21. //   Prefixed keys (E0) are mapped to unique scancodes.
  22. //
  23. // The Pause key requires some extra handling:
  24. //   I have observed the following:
  25. //     Pressing Pause generates these 3 codes: E1 1D 45
  26. //     Pressing Control+Pause (== Break) generates E0 46 which is
  27. //       mapped to an unique virtual scancode.
  28. //     Pressing both Control keys + Pause generates Pause and not E0 46.  
  29. //     The release codes for Pause (E1 80+1D 80+45) and Control+Pause
  30. //       (E0 80+46) are always generated after the press codes !
  31. //       Releasing Pause or Control+Pause generates nothing - this is the
  32. //       reason that there is no scancode for these, only the shift toggles.
  33. //     The Pause key is the only key that generates E1.
  34. //   Implementation:
  35. //     The only thing to care for is the code 1D (KB_SCAN_LCONTROL)
  36. //       in combination with the prefix count. 
  37. //       This code is mapped to a special virtual key so that the
  38. //       current shift status won't get touched.
  39. //     Fortunately E0 45 is never generated, so
  40. //       the E1 1D 45 conversion works fine.
  41. //
  42. // The Print key is also somewhat unusual:
  43. //   normally it generates E0 37, but when Alt is pressed then 54
  44. ************************************************************************/
  45.  
  46.  
  47. #if defined(__BORLANDC__) && defined(__KB_MSDOS16)
  48. static void interrupt far _my_keyint()
  49. {
  50.     unsigned char _t_scan;
  51.     unsigned short _t_shift;
  52.  
  53. #elif defined(__EMX__) && defined(__KB_MSDOS)
  54. static void _my_keyint()
  55. {
  56.     unsigned char _t_scan;
  57.     unsigned short _t_shift;
  58.  
  59. #elif defined(__DJGPP__) && defined(__KB_MSDOS)
  60. static void _my_keyint(_go32_dpmi_registers *regs)
  61. {
  62.     unsigned char _t_scan;
  63.     unsigned short _t_shift;
  64.  
  65. #elif defined(__GO32__) && defined(__KB_MSDOS)
  66.     /* stop djgpp v1 messing up with stack reads */
  67.     static unsigned char _t_scan;
  68.     static unsigned short _t_shift;
  69. static void _my_keyint(_go32_dpmi_registers *regs)
  70. {
  71.  
  72. #elif defined(__WATCOMC__) && defined(__KB_MSDOS)
  73. static void __interrupt __far _my_keyint(union INTPACK regs)
  74. {
  75.     unsigned char _t_scan;
  76.     unsigned short _t_shift;
  77.  
  78. #elif defined(__KB_LINUX)
  79.  
  80.     /* note: this is NOT an interrupt handler */
  81. #if defined(KB_LINUX_MEDIUMRAW)
  82. static void _my_mediumraw_handler(unsigned char _t_scan)
  83. #else
  84. static void _my_raw_handler(unsigned char _t_scan)
  85. #endif
  86. {
  87.     unsigned short _t_shift;
  88.  
  89. #else
  90. #  error unsupported compiler
  91. #endif
  92.  
  93.  
  94. #if defined(__KB_MSDOS)
  95.     /* read keyboard byte */
  96.     _t_scan = KB_INP8(0x60);
  97.  
  98.     /* tell the XT keyboard controller to clear the key */
  99.     /* this is only necessary on XT's */
  100. #if defined(__KB_MSDOS16)
  101.     {
  102.     /* TODO: do we have to care about slow I/O on fast machines ? */
  103.     unsigned char _t_tmp = KB_INP8(0x61);
  104.     KB_OUTP8(0x61,_t_tmp | 0x80);
  105.     KB_OUTP8(0x61,_t_tmp & 0x7f);
  106.     }
  107. #endif
  108. #endif
  109.  
  110.  
  111.     if (kb_handler_callback)
  112.         kb_handler_callback(_t_scan);
  113.  
  114.  
  115. #if defined(KB_DEBUG)
  116.     /* store port value in buffer */
  117.     *_kb_port_buffer_head++ = _t_scan;    
  118.     if (_kb_port_buffer_head >= _kb_port_buffer_end)
  119.         _kb_port_buffer_head = _kb_port_buffer_start;
  120. #endif
  121.  
  122.  
  123. #if !defined(KB_LINUX_MEDIUMRAW)
  124.     if (_t_scan >= 0xe0)
  125.     {
  126.         if (_t_scan <= 0xe1)            /* E0, E1: key prefix */
  127.         {
  128.             _t_prefix = _t_scan - (0xe0 - 1);    /* prefix count */
  129.         }
  130.         else if (_t_scan == 0xff)        /* handle overflow */
  131.         {
  132.             /* try it: press a lot of keys */
  133.             _t_prefix = 0;
  134.             _kb_shift |= KB_SHIFT_OVERFLOW;
  135.         }
  136.         else                        
  137.         {
  138.             /* ignore unknown keys */
  139.             _t_prefix = 0;
  140.             _kb_shift |= KB_SHIFT_UNKNOWN;
  141.         }
  142.     }
  143.     else 
  144. #endif
  145.  
  146.     if (_t_scan & 0x80)            /* key was released */
  147.     {
  148.         _t_scan &= 0x7f;
  149. #if !defined(KB_LINUX_MEDIUMRAW)
  150.         if (_t_scan > KB_SCAN_MAX_RAW)
  151.         {
  152.             _t_scan = KB_SCAN_UNKNOWN;
  153.             _t_prefix = 0;
  154.         }
  155.         else if (_t_prefix > 0)            /* convert scancode */
  156.         {
  157.             if (--_t_prefix > 0)
  158.                 _t_scan = (_t_scan == KB_SCAN_LCONTROL) ?
  159.                     KB_SCAN_UNUSED_VIRTUAL : KB_SCAN_UNKNOWN;
  160.             else
  161.                 _t_scan = _kb_prefix_scancode[_t_scan];
  162.         }
  163. #endif
  164.  
  165.         _t_shift = _kb_shift_state_table[_t_scan];
  166.  
  167.         if (_t_shift & KB_SHIFT_UNKNOWN)
  168.             _kb_shift |= KB_SHIFT_UNKNOWN;
  169.         else if (_kb_key[_t_scan])
  170.         {
  171.             _kb_key[_t_scan] = 0;
  172.             _t_shift &= KB_SHIFT_MASK_SHIFT;
  173.             _kb_shift &= ~_t_shift;        /* clear bit */
  174.             --_kb_keys_pressed;
  175.         }
  176.     }
  177.  
  178.     else                                /* key was pressed */
  179.     {
  180. #if !defined(KB_LINUX_MEDIUMRAW)
  181.         if (_t_scan > KB_SCAN_MAX_RAW)
  182.         {
  183.             _t_scan = KB_SCAN_UNKNOWN;
  184.             _t_prefix = 0;
  185.         }
  186.         else if (_t_prefix > 0)            /* convert scancode */
  187.         {
  188.             if (--_t_prefix > 0)
  189.                 _t_scan = (_t_scan == KB_SCAN_LCONTROL) ?
  190.                     KB_SCAN_UNUSED_VIRTUAL : KB_SCAN_UNKNOWN;
  191.             else
  192.                 _t_scan = _kb_prefix_scancode[_t_scan];
  193.         }
  194. #endif
  195.  
  196.         _t_shift = _kb_shift_state_table[_t_scan];
  197.  
  198.         if (_t_shift & KB_SHIFT_UNKNOWN)
  199.             _kb_shift |= KB_SHIFT_UNKNOWN;
  200.         else if (!_kb_key[_t_scan])
  201.         {
  202.             _kb_shift ^= _t_shift;                /* toggle shift status */
  203.             if (!(_t_shift & KB_SHIFT_VIRTUAL))    /* do not count virtual keys */
  204.             {
  205.                 _kb_key[_t_scan] = 1;
  206.                 _kb_last_key = _t_scan | (_kb_shift << 8);
  207. #if (USHRT_MAX > 0xffff)
  208.                 _kb_last_key &= 0xffff;
  209. #endif
  210.                 ++_kb_keys_pressed;
  211.             }
  212.         }
  213.         else if (_kb_flags & KB_FLAG_REPEAT_OFF)
  214.             _t_shift |= KB_SHIFT_NO_PRESS;
  215.  
  216.         if (!(_t_shift & KB_SHIFT_NO_PRESS))    /* if this key stores a press */
  217.         {
  218.             /* store keypress: scan code + low bits of shift state */
  219.             *_key_buffer_head++ = _t_scan;
  220.             *_key_buffer_head++ = (unsigned char) _kb_shift;
  221.  
  222.             /* adjust pointers */
  223.             if (_key_buffer_head >= _key_buffer_end)
  224.                 _key_buffer_head = _key_buffer_start;
  225.             if (_key_buffer_head == _key_buffer_tail)    /* buffer full */
  226.             {
  227.                 _key_buffer_tail += 2;
  228.                 if (_key_buffer_tail >= _key_buffer_end)
  229.                     _key_buffer_tail = _key_buffer_start;
  230.             }
  231.         }
  232.  
  233.         /* Emergency exit.
  234.          * Raising a signal or exiting within an interrupt handler is probably
  235.          * no good idea. The DPMI specs also say that an application should not
  236.          * terminate during an interrupt that is reflected from real-mode 
  237.          * to protected-mode.
  238.          * But during development it could be worthwile to try it - if your
  239.          * program locks, a reboot would be necessary anyway.
  240.          * It seems to work with Borland C/Watcom C/djgpp though.
  241.          * note: both control keys have to be pressed
  242.          */
  243.         if (_kb_flags & KB_FLAG_EMERGENCY_EXIT)
  244.         {
  245.             if (!_emergency_done && _kb_key[KB_SCAN_C] &&
  246.                 _kb_key[KB_SCAN_LCONTROL] && _kb_key[KB_SCAN_RCONTROL])
  247.             {
  248.                 _emergency_done = 1;
  249. #if defined(__DJGPP__)
  250.                 /* Internal function that raises SIGINT immediately
  251.                  * after the end of this interrupt.
  252.                  * Do not ignore SIGINT when using emergency-exit !
  253.                  */
  254.                 __asm__ __volatile__ (
  255.                     "  movb $0x79,%%al \n"
  256.                     "  call ___djgpp_hw_exception \n"
  257.                     : : : "%eax", "%ebx", "%ecx", "%edx",
  258.                           "%esi", "%edi", "memory", "cc"
  259.                 );
  260. #else
  261.                 KB_ACKINT();                /* ack. interrupt */
  262.                 _kb_emergency_remove(0);
  263. #if !defined(_KB_NO_SIGNALS)
  264.                 raise(SIGINT);
  265. #endif
  266.                 exit(EXIT_SIG(SIGINT));        /* exit if SIGINT is ignored */
  267. #endif
  268.             }
  269.         }
  270.     }
  271.  
  272.  
  273.     KB_ACKINT();                /* ack. interrupt */
  274. }
  275.  
  276.  
  277. /*
  278. vi:ts=4
  279. */
  280.